using net_work.Common;
using net_work.Common.Request;
using net_work.Common.Result;
using net_work.Data.DTO.Appr;
using net_work.Data.Enum.Appr;
using net_work.Data.VO.Appr;
using net_work.IRepository.Appr;
using net_work.IRepository.Sys;
using net_work.IRepository.System;
using net_work.IService.Appr;
using net_work.Rules.Utils;

namespace net_work.Service.Appr;

public class ApprovalService(
    ITransactionManager transactionManager,
    IRuleEngineUtils ruleEngineUtils,
    IUserContext userContext,
    IApprovalInstanceHistoryRepository approvalInstanceHistoryRepository,
    IFlowRepository flowRepository,
    IApprovalInstanceRepository approvalInstanceRepository,
    ITeacherRepository teacherRepository,
    IFlowNodeRepository flowNodeRepository)
    : IApprovalService
{
    public Task<PagedResult<ApprovalInstanceWithHistoryResult>> GetListWithHistory(PagedRequest pagedRequest)
    {
        return approvalInstanceRepository.GetListAsync(pagedRequest);
    }

    public Task<PagedResult<ApprovalInstanceToDoResult>> GetToDoList(PagedRequest pagedRequest)
    {
        return approvalInstanceRepository.GetToDoListAsync(pagedRequest);
    }

    public async Task<int> Start(ApprovalInstanceAddRequest approvalInstanceAddRequest)
    {
        return await approvalInstanceRepository.InsertAsync(approvalInstanceAddRequest) > 0 ? 1 : -1;
    }

    public async Task<int> Submit(ApprovalSubmit approvalSubmit)
    {
        var approvalInstance = await approvalInstanceRepository.GetByIdAsync(approvalSubmit.InstanceId);
        if (approvalInstance == null)
        {
            return -1;
        }

        var flow = await flowRepository.GetByIdAsync(approvalInstance.FlowId);
        if (flow?.BeginFlowNodeId == null)
        {
            return -1;
        }

        var flowNodeId = approvalInstance.CurrentFlowNodeId ?? flow.BeginFlowNodeId.Value;
        var flowNode = await flowNodeRepository.GetByIdAsync(flowNodeId);
        if (flowNode == null)
        {
            return -1;
        }

        try
        {
            await transactionManager.BeginTransactionAsync();

            var approvalInstanceHistoryId = await approvalInstanceHistoryRepository.InsertAsync(
                new ApprovalInstanceHistoryAddRequestBackend
                {
                    Remark = approvalSubmit.Remark,
                    Result = approvalSubmit.Result,
                    Content = approvalSubmit.Content,
                    InstanceId = approvalSubmit.InstanceId,
                    FlowNodeId = flowNodeId
                });
            if (approvalInstanceHistoryId <= 0)
            {
                throw new InvalidOperationException("流程历史记录插入失败");
            }

            var pagedResult = await approvalInstanceHistoryRepository.GetPagedAsync(new PagedRequest(1,
                PageSizeEnum.Unlimited,
                [
                    new FilterCondition("InstanceId", FilterOperator.Equals, approvalSubmit.InstanceId),
                    new FilterCondition("FlowNodeId", FilterOperator.Equals, flowNodeId)
                ]));
            if (pagedResult.TotalRecords <= 0)
            {
                throw new InvalidOperationException("流程历史记录不存在");
            }

            long? deptId = null;
            var taskTotalCount = 1;
            if (userContext.UserRole != "STUDENT")
            {
                var teacherPagedAsync = await teacherRepository.GetTeacherPagedAsync(new PagedRequest(1,
                    PageSizeEnum.Unlimited,
                    [new FilterCondition("UserId", FilterOperator.Equals, userContext.UserId)]));
                if (teacherPagedAsync.TotalRecords > 0)
                {
                    deptId = teacherPagedAsync.Data.First().DepId;
                }

                if (flowNode.ProcessingType == NodeProcessingType.Dept)
                {
                    if (deptId != flowNode.ProcessingId)
                    {
                        throw new InvalidOperationException("当前用户不是该流程节点的处理部门，无法处理该流程");
                    }

                    var pagedAsync = await teacherRepository.GetTeacherPagedAsync(new PagedRequest(1,
                        PageSizeEnum.Unlimited,
                        [new FilterCondition("DepId", FilterOperator.Equals, flowNode.ProcessingId)]));
                    taskTotalCount = pagedAsync.TotalRecords;
                }
            }

            var approvalSubmitInfo = new ApprovalSubmitInfo()
            {
                FlowId = flow.Id,
                InstId = approvalInstance.Id,
                NodeId = flowNodeId,
                SubmitterId = userContext.UserId,
                SubmitterRole = userContext.UserRole,
                SubmitterDeptId = deptId,
                BusinessCode = flow.BusinessCode,
                BusinessEntityId = approvalInstance.BusinessId,
                ProcessingType = flowNode.ProcessingType,
                ProcessingId = flowNode.ProcessingId,
                SuccessType = flowNode.SuccessType,
                SuccessConfig = flowNode.SuccessConfig,
                TaskTotalCount = taskTotalCount,
                ApprovedCount = pagedResult.Data.Where(h =>
                    h.Result == ApprovalResult.Success && h.UpdatedTime >= approvalInstance.UpdatedTime).Count(),
                UnApprovedCount = pagedResult.Data.Where(h =>
                    h.Result == ApprovalResult.Fail && h.UpdatedTime >= approvalInstance.UpdatedTime).Count()
            };

            ruleEngineUtils.ExecuteRules([
                approvalSubmitInfo
            ]);

            if (approvalSubmitInfo.IsSkip)
            {
                if (approvalSubmitInfo.SkipResult == null)
                {
                    throw new InvalidOperationException("跳过结果不能为空，系统异常，请联系管理员");
                }

                await approvalInstanceRepository.Skip(approvalInstance.Id, approvalSubmitInfo.SkipResult.Value);
            }

            await transactionManager.CommitTransactionAsync();
            return 1;
        }
        catch (Exception e)
        {
            await transactionManager.RollbackTransactionAsync();
            return -1;
        }
    }
}